<template>
	<div class="model_index pos_r">
		<canvas id="three" canvas-id="three_canvas" type="webgl" style="width: 100%; height:100%;"
			@touchstart="touchStart" @touchmove="touchMove" @touchend="touchEnd"></canvas>
		<view class="pos_a reduction flex_center flex_column">
			<image mode="widthFix" @click="reductionFun" v-throttle src="@/static/image/buy/reduction_icon.png"
				alt="" />
		</view>
	</div>
</template>

<script>
	import * as THREE from "@/uni_modules/three-weapp/libs/three.weapp.js";
	import gLTF from "@/uni_modules/three-weapp/jsm/loaders/GLTFLoader.js";
	import {
		OrbitControls
	} from "@/uni_modules/three-weapp/jsm/controls/OrbitControls";
	let canvasT = null;
	export default {
		props: {
			//主图
			goodsImg: {
				type: String,
				default: "https://dreamofcity.oss-cn-chengdu.aliyuncs.com/pre/backstage/img/1722587867918.jpg"
			},
			//是否开启缩放
			enableZoom: {
				type: Boolean,
				default: false
			},
			//用户手势旋转
			enableRotate: {
				type: Boolean,
				default: true
			},
			// 用户手势平移相机
			enablePan: {
				type: Boolean,
				default: false
			},
			// 是否开启自动旋转
			autoRotate: {
				type: Boolean,
				default: true
			},

			// 画面显示倍数
			according: {
				type: Number,
				default: 5
			},
		},
		data() {
			return {
				menuInfo: null, //屏幕比例
				rotateYAngle: 1, //旋转角度 1正旋转 -1反向旋转
				isLandscape: false, //是否是横屏
				// Wscale: 1.39,
				// Hscale: 0.71,
				Wscale: 1.48,
				Hscale: 0.66,

				// loading
				loading: true,
				clock: new THREE.Clock(),
				manager: new THREE.LoadingManager(),
				camera: null, //照相机
				scene: null, //模型
				mixer: null, //动画混淆
				controls: null,
				renderer: null,


				loadAsyncTexture: null, //贴图内容
				// 模型内容
				modelObj: {
					src: "https://oss.manguyishu.com/mangu/front/model/frame/scene.gltf",
					// src: "https://threejsfundamentals.org/threejs/resources/models/cartoon_lowpoly_small_city_free_pack/scene.gltf",
					x: -60,
					y: -80,
					z: 20,
				},
				// 背后logo图
				logo: "https://oss.manguyishu.com/mangu/front/logo.png",
				// 手势监听
				mc: null,
			};
		},
		watch: {
			goodsImg: {
				handler(newVal, oldVal) {
					if (newVal) {
						console.log("主图", newVal);
						this.scene = new THREE.Scene();
						this.$nextTick(async () => {
							this.initThree();

						});
					}
				},
				immediate: false,
				deep: true,
			},
			loading: {
				handler(newVal, oldVal) {
					console.log('加载---', newVal)

					if (!newVal) {
						this.$emit("load");
					}
				},
			},
		},
		mounted() {
			this.menuInfo = this.$store.getters["sys/getMenuInfo"];
		},
		methods: {
			touchStart(e) {
				THREE.global.touchEventHandlerFactory('canvas', 'touchstart')(e)
			},
			touchMove(e) {
				THREE.global.touchEventHandlerFactory('canvas', 'touchmove')(e)
			},
			touchEnd(e) {
				THREE.global.touchEventHandlerFactory('canvas', 'touchend')(e)
			},
			// 重置视角
			reductionFun() {
				// 透视投影照相机
				this.camera.position.set(0, 0, 350); //x,y,z    z拉远可缩小
				// 模型中心
				this.controls = new OrbitControls(this.camera, this.renderer.domElement);
				// this.controls.autoRotate = this.autoRotate;
			},
			// 渲染gltf模型
			async loadingGLTF() {
				let GLTFLoader = gLTF(THREE);
				const gltfLoader = new GLTFLoader();
				// const gltfLoader = new THREE.GLTLoader();
				let that = this;
				let obj = this.modelObj;
				await gltfLoader.load(obj.src,
					async (gltf) => {
						// 3d模型大小
						if (this.isLandscape) {
							//判断是横屏
							obj.x = 80;
							obj.y = -66;
							gltf.scene.rotateZ(Math.PI / 2);
						}
						gltf.scene.scale.set(this.according, this.according, this.according); // scale here
						gltf.scene.position.set(obj.x, obj.y, obj.z);

						const model = gltf.scene;
						//遍历模型每部分
						await model.traverse(async (o) => {
							if (o.isMesh) {
								// 模型是否展示阴影
								o.castShadow = true;
								o.receiveShadow = false;
								that.$nextTick(() => {
									// 给模型添加原有文件颜色和贴图
									o.material.emissive = o.material.color;
									o.material.emissiveMap = o.material.map;

								});
							}
						});
						that.scene.add(model);
						that.$nextTick(() => {
							that.loading = false;
							console.log('渲染成功', that.loading);
						})
					})
			},
			// 贴图画板图案
			materialLoadAsync() {
				let that = this;
				let texLoader = new THREE.TextureLoader();
				new Promise((resolve, reject) => {
					texLoader.load(this.goodsImg, resolve, undefined, reject);
				}).then((texture) => {
					// 矩形平面
					var planeGeometry = new THREE.PlaneGeometry(115, 160, 4, 4);
					// 创建一个材质，设置为双面渲染
					var planeMaterial = new THREE.MeshBasicMaterial({
						transparent: true,
						map: texture,
						side: THREE.DoubleSide, // 设置材质为双面渲染
						lights: true,
					});
					if (texture.image) {
						// 根据纹理的宽高比和平面的宽高比，计算需要的缩放比例
						var width = texture.image.width; // Current image width
						var height = texture.image.height; // Current image height
						let texture_aspect_ratio = width / height;
						this.isLandscape = width > height;
						let scale_x = 1;
						let scale_y = 1;
						if (this.isLandscape) {
							// 横屏幕
							// 设置纹理旋转角度
							planeGeometry = new THREE.PlaneGeometry(160, 115, 4, 4);
							texture_aspect_ratio = height / width;
							if (texture_aspect_ratio > this.Hscale) {
								scale_y = (this.Hscale * width) / height;
							} else {
								scale_x = (this.Wscale * height) / width;
							}
							// 设置纹理的偏移和重复以进行居中和适应
							texture.offset.set((0.5 - scale_x / 2), (0.5 - scale_y / 2));
						} else {
							// 竖屏幕
							if (texture_aspect_ratio >= this.Hscale) {
								scale_x = this.Hscale / texture_aspect_ratio;
							} else {
								scale_y = texture_aspect_ratio;
							}
							// 设置纹理的偏移和重复以进行居中和适应
							texture.offset.set((0.5 - scale_x / 2), (0.5 - scale_y / 2));
						}
						texture.repeat.set(scale_x, scale_y);
					}
					texture.needsUpdate = true;

					var plane = new THREE.Mesh(planeGeometry, planeMaterial);
					// 旋转角度设置
					// plane.rotation = rotation;
					plane.colorSpace = THREE.SRGBColorSpace;
					plane.encoding = THREE.sRGBEncoding; //和渲染器.outputEncoding一样值
					plane.wrapS = THREE.RepeatWrapping;
					plane.wrapT = THREE.RepeatWrapping;
					plane.castShadow = true;
					plane.needsUpdate = true;

					//偏移位置
					plane.position.set(2, 0, 1);
					if (this.isLandscape) {
						plane.position.set(0.5, -3, 1.5);
					}
					// 使平面就接收物体投掷过来的阴影
					plane.receiveShadow = false;

					this.scene.add(plane);
					this.$nextTick(() => {
						this.loadingGLTF();
					})
				});
			},
			// 画背后logo
			initLogo() {
				// 矩形平面
				var planeGeometry = new THREE.PlaneGeometry(40, 40, 4, 4);
				let texture = new THREE.TextureLoader().load(this.logo);

				// 创建一个材质，设置为双面渲染
				var planeMaterial = new THREE.MeshBasicMaterial({
					transparent: true,
					map: texture,
					side: THREE.DoubleSide, // 设置材质为双面渲染
					lights: true,
				});
				var plane = new THREE.Mesh(planeGeometry, planeMaterial);
				// 旋转角度设置
				plane.rotation.y = Math.PI;
				plane.colorSpace = THREE.SRGBColorSpace;
				plane.encoding = THREE.sRGBEncoding; //和渲染器.outputEncoding一样值
				plane.castShadow = true;
				plane.needsUpdate = true;

				//偏移位置
				plane.position.set(0, 0, -0.5);
				// 使平面就接收物体投掷过来的阴影
				plane.receiveShadow = false;

				this.scene.add(plane);
			},
			// 透视投影照相机
			initCamera() {
				new Promise((resolve, reject) => {

					const query = uni.createSelectorQuery().in(this);
					let that = this;
					query.select("#three").boundingClientRect(data => {
						const fov = 45;
						const aspect = data.width / data.height; // the canvas default
						const near = 0.1;
						const far = 1000;
						that.camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
						that.reductionFun();
						that.$nextTick(() => {
							// 场景配置
							that.initControls();
						})
						resolve();
					}).exec();
				})
			},
			// 光源
			initLight() {
				// 设置环境背景颜色
				// this.scene.background = new THREE.Color("transparent");

				// 点光源
				var pointLight = new THREE.PointLight();
				pointLight.color = new THREE.Color(0xffffff);
				pointLight.position.set(0, 100, 100); //角度
				pointLight.intensity = 1; //光源强度
				this.scene.add(pointLight);

				/*创建辅助工具*/
				//辅助线
				var axes = new THREE.AxesHelper(600);
				// this.scene.add(axes);
			},
			// 初始化场景配置
			initControls() {
				//以自动围绕目标旋转。
				this.controls.autoRotate = false;
				//设置相机距离原点的最远距离
				// this.controls.minDistance = 50;
				//设置相机距离原点的最远距离
				// this.controls.maxDistance = 200;
				//设置相机距离原点的最远距离
				this.controls.minDistance = 50;
				//设置相机距离原点的最远距离
				this.controls.maxDistance = 500;

				// 阻尼惯性（拖拽惯性）
				this.controls.enableDamping = true;
				//动态阻尼系数 就是鼠标拖拽旋转灵敏度
				this.controls.dampingFactor = 0.1;
				//是否开启缩放
				this.controls.enableZoom = this.enableZoom;
				//用户手势旋转
				this.controls.enableRotate = this.enableRotate;

				//是否开启平移相机
				this.controls.enablePan = this.enablePan;
				//是否开启垂直平移相机
				this.controls.hylMovePanY = this.enablePan;
				// 是否开启水平移动相机
				this.controls.hylMovePanX = this.enablePan;
				// 是否可以上下平移
				this.controls.screenSpacePanning = this.enablePan;

				//是否使用键盘
				this.controls.enableKeys = true;
				// 缩放限制
				this.controls.maxZoom = 1;
				this.controls.minZoom = 0.6;
				this.controls.zoomSpeed = 1;

			},
			// 初始化
			async initThree() {


				const query = uni.createSelectorQuery().in(this);
				let that = this;
				await query.select("#three").node().exec(async res => {
					const canvas = res[0].node;
					canvasT = THREE.global.registerCanvas(canvas);

					// 渲染器
					that.renderer = new THREE.WebGLRenderer({
						canvas: canvasT,
						antialias: true, //抗锯齿
						alpha: true, //配合设置背景透明
						setSize: true,
						preserveDrawingBuffer: true, //是否保留缓
						sortObjects: true, //定义渲染器是否应对对象进行排序
						physicalCorrectLights: true, //是否使用物理上正确的照明模式
						gammaFactor: 1, //伽马基础值
					});
					that.renderer.setClearColor(0xffffff, 0.0); // 设置清除颜色为黑色，透明度为0
					that.renderer.setClearAlpha(0);

					// 色差
					that.renderer.outputEncoding = THREE.sRGBEncoding;
					//开启渲染气阴影效果
					that.renderer.shadowMap.enabled = false;
					that.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
					// 开启HiDPI设置
					that.renderer.setPixelRatio(this.menuInfo.devicePixelRatio); //获取预览窗口比例 渲染比例
					that.renderer.setSize(that.menuInfo.windowWidth, that.menuInfo
						.windowHeight); //设置渲染区域尺寸
					canvasT.appendChild(that.renderer.domElement);


					// 透视投影照相机
					await that.initCamera();

					// 创建光源
					that.initLight();


					// 启动页面渲染
					that.$nextTick(async () => {
						await that.materialLoadAsync();

						that.initLogo();
						that.animate();
					});
				});

			},

			animate() {
				if (this.mixer) {
					const delta = this.clock.getDelta(); // 获取自上次调用的时间差
					this.mixer.update(delta);
				}
				if (this.resizeRendererToDisplaySize(this.renderer)) {
					const canvas = this.renderer.domElement;
					//旋转动画
					this.camera.aspect = canvas.clientWidth / canvas.clientHeight;
					this.camera.updateProjectionMatrix();
				}

				// 更换左右摆动逻辑
				let {
					_y
				} = this.scene.rotation;
				if (_y >= 0.5) this.rotateYAngle = -1;
				if (_y <= -0.5) this.rotateYAngle = 1;
				if (this.autoRotate) this.scene.rotateY(this.rotateYAngle * 0.002); //每次绕y轴旋转0.01弧度

				this.renderer.render(this.scene, this.camera);
				//请求再次执行渲染函数render，渲染下一帧
				canvasT.requestAnimationFrame(this.animate);
				this.controls.update();
			},
			resizeRendererToDisplaySize(renderer) {
				const canvas = renderer.domElement;
				var width = this.menuInfo.windowWidth;
				var height = this.menuInfo.windowHeight;
				var canvasPixelWidth = canvas.width / this.menuInfo.devicePixelRatio;
				var canvasPixelHeight = canvas.height / this.menuInfo.devicePixelRatio;
				const needResize =
					canvasPixelWidth !== width || canvasPixelHeight !== height;
				if (needResize) {
					renderer.setSize(width, height, false);
				}
				return needResize;
			},
		},
	};
</script>

<style scoped lang="scss">
	.model_index {
		width: 100%;
		height: 100%;
		position: relative;

		.loading {
			position: absolute;
			left: 0;
			top: 0;
			right: 0;
			bottom: 0;

			img {
				width: 140rpx;
			}
		}
	}

	#three {
		width: 100%;
		height: 100%;
		background: transparent !important;
	}

	.reduction {
		right: 40rpx;
		bottom: 60rpx;
		z-index: 9;
		display: inline-flex;
		color: #fff;
		width: 44rpx;

		image {
			width: 100%;
			margin-bottom: 60rpx;

			&:last-child {
				margin: 0;
			}
		}
	}

	// 操作弹窗
	::v-deep .u-popup__content {
		background: transparent;
	}

	.operation_div {
		width: 450rpx;

		.img_div {
			width: 100%;
		}

		.know {
			width: 200rpx;
			height: 72rpx;
			border-radius: 36rpx;
			background: rgba(255, 255, 255, 0.14);
			font-size: 32rpx;
			color: #eeeeee;
			font-weight: bold;
			font-family: PingFang SC-Bold;
			margin-top: 120rpx;
		}
	}
</style>